/**
 * @file STL_HttpServer.h
 * @author Derek Liu (yjkhtddx@sina.com)
 * @brief 
 * @version 0.1
 * @date 2021-02-07
 * 
 * @copyright Copyright Sci-Tech Laboratories (c) 2021
 * 
 */

#ifndef __STL_HTTP_SERVER_H__
#define __STL_HTTP_SERVER_H__

#include <string>
#include <stdint.h>
#include <functional>
#include <thread>
#include <mutex>
#include <list>
#include <queue>
#include <memory>
#include "STL_TcpServer.h"
#include "STL_HttpParser.h"
#include "STL_HttpRequest.h"
#include "STL_HttpResponse.h"
#include "STL_Tools.h"
#include "STL_Text.h"

namespace STL
{

    class STL_HttpServer
    {
    public:
        typedef enum Status_e
        {
            None,
            Init,
            Listen,
            Working,
            ERROR,
            Over
        } Status;

        typedef struct HttpServerConfig_t
        {
            std::string ip = "0.0.0.0";
            uint16_t port = 80;
            HttpServerConfig_t(uint16_t port)
            {
                this->port = port;
            }
            HttpServerConfig_t(std::string ip, uint16_t port)
            {
                this->ip = ip;
                this->port = port;
            }
        } HttpServerConfig;
        typedef std::function<void(std::shared_ptr<STL_HttpRequest> /*req*/, std::shared_ptr<STL_HttpResponse> /*res*/, std::function<void(void)> /*callback*/)> HandlerFunction;

    public:
        STL_HttpServer(HttpServerConfig config);
        ~STL_HttpServer();

    public:
        void addHandler(const std::string path, HandlerFunction handler)
        {
            m_handlers[path] = handler;
        };
        void removeHandler(const std::string path)
        {
            m_handlers.erase(path);
        };

    public:
        void addRoute(std::string path)
        {
            if (path.empty())
                return;
            if (path.size() == 1 && path == "/")
                return;
            if (path.substr(0, 1) != "/")
                path = std::string("/") + path;
            if (path.substr(path.size() - 1) == "/")
                path = path.substr(0, path.size() - 1);
            m_routes.push_back(path);
        }
        std::string getHandlerPath(const std::string path)
        {
            for (int i = 0; i < m_routes.size(); i++)
            {
                if (STL_Text::string_start_with(path, m_routes[i]))
                {
                    return path.substr(m_routes[i].size());
                }
            }
            return path;
        }

    private:
        std::vector<std::string> m_routes;
        std::map<std::string, HandlerFunction> m_handlers;
        void handler(int socketId, std::shared_ptr<STL_HttpRequest> req);

    public:
        STL_STATUS_CALLBACK(STL_HttpServer::Status);

    private:
        std::map<int /*fd*/, std::shared_ptr<STL_HttpParser> /*socketinfo*/> m_handlerMap;

    private:
        HttpServerConfig m_config;

    private:
        STL_TcpServer *m_tcpServer;
    };
} // namespace STL

#endif //__STL_HTTP_SERVER_H__